/*
 * SyncResource.java
 *
 * Created on April 12, 2007, 1:39 PM
 *
 * To change this template, choose Tools | Template Manager
 * and open the template in the editor.
 */

package org.atomojo.auth.service.app;

import java.sql.SQLException;
import java.util.UUID;
import java.util.logging.Level;
import org.atomojo.app.client.XMLRepresentationParser;
import org.atomojo.auth.service.db.AuthDB;
import org.atomojo.auth.service.db.Realm;
import org.atomojo.auth.service.db.RealmUser;
import org.atomojo.auth.service.db.User;
import org.atomojo.auth.service.db.XML;
import org.infoset.xml.Document;
import org.infoset.xml.Element;
import org.infoset.xml.XMLException;
import org.infoset.xml.util.DocumentDestination;
import org.restlet.Request;
import org.restlet.data.CharacterSet;
import org.restlet.data.MediaType;
import org.restlet.data.Status;
import org.restlet.representation.Representation;
import org.restlet.representation.StringRepresentation;
import org.restlet.resource.ServerResource;

/**
 *
 * @author alex
 */
public class RealmUsersResource extends ServerResource
{
   
   AuthDB db;
   XMLRepresentationParser parser = XML.createParser();
   /** Creates a new instance of SyncResource */
   public RealmUsersResource() {
      setNegotiated(false);
   }

   protected void doInit() {
      db = (AuthDB)getRequest().getAttributes().get(AuthApplication.DB_ATTR);
      parser.addAllowedElement(XML.USER_NAME);
   }
   
   public Representation get()
   {
      try {
         Realm realm  = fetch();
         if (realm!=null) {
            Representation entity = new DBIteratorRepresentation(MediaType.APPLICATION_XML,XML.USERS_NAME,db.getRealmUsers(realm));
            entity.setCharacterSet(CharacterSet.UTF_8);
            return entity;
         } else {
            getResponse().setStatus(Status.CLIENT_ERROR_NOT_FOUND);
            return new StringRepresentation("Realm not found.");
         }
      } catch (IllegalArgumentException ex) {
         getResponse().setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
         return new StringRepresentation("Invalid UUID value for realm id.");
      } catch (SQLException ex) {
         getContext().getLogger().log(Level.SEVERE,"Cannot get users from database.",ex);
         getResponse().setStatus(Status.SERVER_ERROR_INTERNAL);
         return new StringRepresentation("Database error, see logs.");
      }
   }
   
   public Representation post(Representation entity)
   {
      if (!XMLRepresentationParser.isXML(entity.getMediaType())) {
         getResponse().setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
         return new StringRepresentation("Non-XML media type for entity body: "+entity.getMediaType().getName());
      }
      Document doc = null;
      
      try {
         DocumentDestination dest = new DocumentDestination();
         parser.parse(entity,dest);
         doc = dest.getDocument();
         Element top = doc.getDocumentElement();
         String sid = top.getAttributeValue("id");
         String alias = top.getAttributeValue("alias");
         if (sid==null && alias==null) {
            getResponse().setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
            return new StringRepresentation("One of the 'id' or 'alias' attributes must be specified.");
         }
         UUID id = null;
         if (sid!=null) {
            try {
               id = UUID.fromString(sid);
            } catch (IllegalArgumentException ex) {
               getResponse().setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
               return new StringRepresentation("Invalid UUID value for user id.");
            }
         }
         String password = top.getAttributeValue("password");
         Element name = top.getFirstElementNamed(XML.NAME_NAME);
         Element email = top.getFirstElementNamed(XML.EMAIL_NAME);

         if (alias!=null && !User.isAlias(alias)) {
            getResponse().setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
            return new StringRepresentation("The alias '"+alias+"' does not contain all letters or digits.");
         }
         
         try {
            Realm realm = null;
            try {
               realm = fetch();
            } catch (IllegalArgumentException ex) {
               getResponse().setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
               return new StringRepresentation("Invalid UUID value for realm id.");
            }
            if (realm==null) {
               getResponse().setStatus(Status.CLIENT_ERROR_NOT_FOUND);
               return new StringRepresentation("Realm not found.");
            }
            User user = null;
            if (id!=null) {
               user = db.getUser(id);
               if (user==null) {
                  getResponse().setStatus(Status.CLIENT_ERROR_NOT_FOUND);
                  return new StringRepresentation("User with id "+id+" not found.");
               } else if (alias==null && user.getAlias()==null) {
                  getResponse().setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
                  return new StringRepresentation("The global user "+id+" does not have an alias and the alias was not specified on the request.");
               }
            }
            if (user==null) {
               // we have a request to create a realm user not tied to an existing user.
               // create a new user and then the realm user
               user = db.createUser(UUID.randomUUID(),null,null,null);
               if (user==null) {
                  // this really shouldn't happen because we don't have an alias
                  getResponse().setStatus(Status.CLIENT_ERROR_NOT_FOUND);
                  return new StringRepresentation("User creation is not available.");
               }
               // set the password if they specified it
               if (password!=null) {
                  user.setPassword(password);
               }
            }
            if (alias!=null && alias.equals(user.getAlias())) {
               // inherit the alias as it is the same
               alias = null;
            }
            
            if (db.isRealmUserAliasAvailable(realm,user,alias)) {
               RealmUser realmUser = db.createRealmUser(realm,user,alias,name==null ? null : name.getText(),email==null ? null : email.getText());
               if (realmUser==null) {
                  getResponse().setStatus(Status.CLIENT_ERROR_EXPECTATION_FAILED);
                  return new StringRepresentation("The realm user could not be created.");
               } else {
                  Representation responseEntity = new DBObjectRepresentation(MediaType.APPLICATION_XML,realmUser);
                  responseEntity.setCharacterSet(CharacterSet.UTF_8);
                  getResponse().setStatus(Status.SUCCESS_CREATED);
                  return responseEntity;
               }
            } else {
               getResponse().setStatus(Status.CLIENT_ERROR_CONFLICT);
               return new StringRepresentation("The alias "+alias+" is not available.");
            }
         } catch (SQLException ex) {
            getContext().getLogger().log(Level.SEVERE,"Realm user creation failed.",ex);
            getResponse().setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
            return new StringRepresentation("User creation refused.");
         }
         
         
      } catch (XMLException ex) {
         getResponse().setStatus(Status.CLIENT_ERROR_BAD_REQUEST);
         return new StringRepresentation("XML parse error: "+ex.getMessage());
      } catch (Exception ex) {
         getLogger().log(Level.SEVERE,"Exception during processing.",ex);
         getResponse().setStatus(Status.SERVER_ERROR_INTERNAL);
         return new StringRepresentation("Exception during processing.");
      }
   }
   
   protected Realm fetch()
      throws SQLException
   {
      /*
      Realm realm = null;
      if (name!=null) {
         realm = db.getRealm(name);
      }
      if (suuid!=null) {
         UUID id = UUID.fromString(suuid);
         realm = db.getRealm(id);
      }
      return realm;
       */
      Realm realm = (Realm)getRequest().getAttributes().get(AuthApplication.REALM_ATTR);
      return realm;
   }
   
  
}
